From d0a2b13923f9053612cb82a98a5275fe8cc06c7a Mon Sep 17 00:00:00 2001 From: robertl Date: Wed, 31 Aug 2005 21:47:26 +0000 Subject: [PATCH] Olaf adds ignrando support. --- gpsbabel/Makefile | 4 +- gpsbabel/README | 11 ++ gpsbabel/ignrando.c | 417 ++++++++++++++++++++++++++++++++++++++++++++ gpsbabel/vecs.c | 7 + 4 files changed, 438 insertions(+), 1 deletion(-) create mode 100644 gpsbabel/ignrando.c diff --git a/gpsbabel/Makefile b/gpsbabel/Makefile index 037069ac2..d631496e3 100644 --- a/gpsbabel/Makefile +++ b/gpsbabel/Makefile @@ -38,7 +38,8 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin_tables.o \ ozi.o nmea.o text.o html.o palmdoc.o netstumbler.o hsa_ndv.o \ igc.o brauniger_iq.o shape.o hiketech.o glogbook.o coastexp.o \ vcf.o overlay.o kml.o google.o lowranceusr.o an1.o tomtom.o \ - tef_xml.o maggeo.o pathaway.o vitosmt.o gdb.o bcr.o coto.o + tef_xml.o maggeo.o pathaway.o vitosmt.o gdb.o bcr.o coto.o \ + ignrando.o FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o reverse_route.o sort.o stackfilter.o trackfilter.o discard.o @@ -202,6 +203,7 @@ html.o: html.c defs.h queue.h gbtypes.h jeeps/gpsmath.h jeeps/gps.h \ jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h \ jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h igc.o: igc.c defs.h queue.h gbtypes.h +ignrando.o: ignrando.c defs.h queue.h gbtypes.h xmlgeneric.h internal_styles.o: internal_styles.c defs.h queue.h gbtypes.h kml.o: kml.c defs.h queue.h gbtypes.h xmlgeneric.h lowranceusr.o: lowranceusr.c defs.h queue.h gbtypes.h diff --git a/gpsbabel/README b/gpsbabel/README index c8ea31061..dc334484e 100644 --- a/gpsbabel/README +++ b/gpsbabel/README @@ -1026,6 +1026,17 @@ THE FORMATS structure. Export to this format is not possible, as this format has too many fields that we never get populated by any other format. + IGNRando + + Input and output support for IGN Rando track files. IGN Rando + is a program mainly used in France for Topo maps. The files + are XML based and are "windows-1252" encoded. Trackpoints come + without timestamp. + + Options: + + index - Use track number from input data for output. + The range is 1 to number of tracks in input. DATA FILTERS diff --git a/gpsbabel/ignrando.c b/gpsbabel/ignrando.c new file mode 100644 index 000000000..c24b4e6e3 --- /dev/null +++ b/gpsbabel/ignrando.c @@ -0,0 +1,417 @@ +/* + + Support for IGN Rando track files, + + Copyright (C) 2005 Olaf Klein, o.b.klein@t-online.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA +*/ + +#include +#include +#include +#include + +#include "defs.h" +#include "cet_util.h" + +#if !NO_EXPAT +#include +static XML_Parser psr; +#endif + +FILE *fin, *fout; + +static route_head *track; +static waypoint *wpt; +static int track_points; +static int track_index; /* index of track we'll write */ +static int track_num; /* current index of track within track_disp_all */ + +static int xmlpoints; +static char xmldir[1024]; +static int xmltag; + +/* options */ +static char *index_opt = NULL; + +static arglist_t ignr_args[] = +{ + {"index", &index_opt, "Index of track to write (if more the one in source)", NULL, ARGTYPE_INT }, + {0, 0, 0, 0 } +}; + +#define MYNAME "IGNRando" + +#define READ_BUFFER_SIZE 16384 + +typedef struct ignr_xmldir_s +{ + int tag; + char *name; +} ignr_xmldir_t; + +static ignr_xmldir_t ignr_xmldir[] = +{ + { 0, "/" }, + { 1, "/RANDONNEE/" }, + { 2, "/RANDONNEE/INFORMATIONS/NB_ETAPES/" }, + { 3, "/RANDONNEE/INFORMATIONS/DESCRIPTION/" }, + { 4, "/RANDONNEE/ETAPE/" }, + { 5, "/RANDONNEE/ETAPE/POSITION/" }, + { 6, "/RANDONNEE/ETAPE/ALTITUDE/" }, + +/* + { , "/RANDONNEE/ENTETE/" }, + { , "/RANDONNEE/ENTETE/VERSION_XML/" }, + { , "/RANDONNEE/ENTETE/VERSION_BASE/" }, + { , "/RANDONNEE/ENTETE/DATE/" }, + { , "/RANDONNEE/ENTETE/HEURE/" }, + { , "/RANDONNEE/INFORMATIONS/" }, + { , "/RANDONNEE/INFORMATIONS/TYPE/" }, + { , "/RANDONNEE/INFORMATIONS/DISTANCE/" }, + { , "/RANDONNEE/INFORMATIONS/DUREE/" }, + { , "/RANDONNEE/INFORMATIONS/DENIVELE_MONTE/" }, + { , "/RANDONNEE/INFORMATIONS/DENIVELE_DESCENTE/" }, + { , "/RANDONNEE/INFORMATIONS/DIFFICULTE/" }, + { , "/RANDONNEE/INFORMATIONS/INTERET/" }, + { , "/RANDONNEE/INFORMATIONS/EMPRISE/" }, + { , "/RANDONNEE/INFORMATIONS/COULEUR/" }, + { , "/RANDONNEE/INFORMATIONS/EPAISSEUR/" }, + { , "/RANDONNEE/INFORMATIONS/STYLE_DE_TRAIT/" }, + { , "/RANDONNEE/INFORMATIONS/COULEUR_BANDE_CENTRALE/" }, + { , "/RANDONNEE/INFORMATIONS/EPAISSEUR_BANDE_CENTRALE/" }, + { , "/RANDONNEE/INFORMATIONS/STYLE_DE_TRAIT_BANDE_CENTRALE/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/PROFIL_NOM/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/PROFIL_DESCENTE/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/PROFIL_PLAT/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/PROFIL_MONTEE/" }, + { , "/RANDONNEE/INFORMATIONS/PROFIL/PROFIL_READONLY/" }, + { , "/RANDONNEE/INFORMATIONS/DISTANCE_PLAT/" }, + { , "/RANDONNEE/INFORMATIONS/IMPRIMER_INSTRUCTIONS/" }, + { , "/RANDONNEE/ETAPE/ETAPE_REMARQUABLE/" }, +*/ + { -1, NULL } +}; + +#if NO_EXPAT +void +ignr_rd_init(const char *fname) +{ + fatal(MYNAME ": This build excluded " MYNAME " support because expat was not installed.\n"); +} + +void +ignr_read(void) +{ +} + +#else + +static void +ignr_strcat(char *dest, const char *src, size_t dest_size) +{ + int len, left; + + len = strlen(dest); + left = dest_size - len - 1; + if (left > 0) + strncpy(dest+len, src, left); +} + +static int +ignr_find_tag(const char *xmldir) +{ + int iter = 0; + char *c; + + while ((c = ignr_xmldir[iter].name)) + { + if (case_ignore_strcmp(xmldir, c) == 0) return iter; + iter++; + } + return -1; +} + +static route_head * +ignr_track(void) +{ + if (track == NULL) + { + track = route_head_alloc(); + track_add_head(track); + } + return track; +} + +static void +ignr_start(void *data, const char *el, const char **attr) +{ + ignr_strcat(xmldir, el, sizeof(xmldir)); + ignr_strcat(xmldir, "/", sizeof(xmldir)); + + xmltag = ignr_find_tag(xmldir); + + if (xmltag == 4) + { + wpt = waypt_new(); + } +} + +static void +ignr_end(void *data, const char *el) +{ + char *c, *cend; + + + if ((xmltag == 4) && (wpt != NULL)) + { + route_add_wpt(ignr_track(), wpt); + wpt = NULL; + track_points++; + } + + cend = xmldir + strlen(xmldir) - 1; + if (cend <= xmldir) fatal(MYNAME ": Error in XML structure!\n"); + + *cend = '\0'; + c = cend; + while (*c != '/') c--; + c++; + + if (strcmp(c, el) != 0) fatal(MYNAME ": Error in XML structure!\n"); + *c = '\0'; + + xmltag = ignr_find_tag(xmldir); +} + +static void +ignr_cdata(void *dta, const XML_Char *s, int len) +{ + char *c; + + if (len < 0) return; + + c = xmalloc(len + 1); + memcpy(c, s, len); + c[len] = '\0'; + + switch(xmltag) + { + case 2: + xmlpoints = atoi(c); + break; + case 3: + if (len > 0) + ignr_track()->rte_desc = xstrdup(c); + break; + + case 5: + if (wpt == NULL) + fatal(MYNAME ": Error in XML structure!\n"); + if (2 != sscanf(c, "%lf,%lf", &wpt->latitude, &wpt->longitude)) + fatal(MYNAME ": Invalid coordinates \"%s\"!\n", c); + break; + case 6: + if (wpt == NULL) + fatal(MYNAME ": Error in XML structure!\n"); + if (1 != sscanf(c, "%lf", &wpt->altitude)) + fatal(MYNAME ": Invalid altitude \"%s\"!\n", c); + break; + } + xfree(c); +} + +static void +ignr_rd_init(const char *fname) +{ + track = NULL; + wpt = NULL; + track_points = 0; + strcpy(xmldir, "/"); + xmltag = -1; + xmlpoints = -1; + + fin = xfopen(fname, "r", MYNAME); + if ((psr = XML_ParserCreate(NULL)) == NULL) + fatal(MYNAME ": Could not create XML parser\n"); + + XML_SetUnknownEncodingHandler(psr, cet_lib_expat_UnknownEncodingHandler, NULL); + XML_SetElementHandler(psr, ignr_start, ignr_end); + XML_SetCharacterDataHandler(psr, ignr_cdata); +} + +static void +ignr_read(void) +{ + int len; + char *buff; + + buff = xmalloc(READ_BUFFER_SIZE); + + while ((len = fread(buff, 1, READ_BUFFER_SIZE, fin))) + { + if (XML_Parse(psr, buff, len, feof(fin)) == 0) + { + fatal(MYNAME ": XML-Parser error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } + + xfree(buff); +} + +#endif + +static void +ignr_rd_deinit(void) +{ + XML_ParserFree(psr); + psr = NULL; + + if ((xmlpoints != -1) && (xmlpoints != track_points)) + fatal(MYNAME ": Number of defined points differs to present number!\n"); + +} + +/* write support */ + +static void +ignr_fprintf(FILE *f, const char *fmt, ...) +{ + char buff[256]; + char *temp = buff; + va_list args; + int i; + + va_start(args, fmt); + + i = vsnprintf(buff, sizeof(buff), fmt, args); + if (i >= sizeof(buff)) + { + temp = xmalloc(i + 1); + i = vsnprintf(temp, i + 1, fmt, args); + } + if (i < 0) + { + fatal(MYNAME ": error in vsnprintf.\n"); + } + else if (i > 0) + { + char eol = temp[i - 1]; + if (eol == '\n') i--; + fwrite(temp, 1, i, f); + if (eol == '\n') fprintf(f, "\x0D\n"); + } + + if (temp != buff) xfree(temp); + va_end(args); +} + +static void +ignr_rw_init(const char *fname) +{ + fout = xfopen(fname, "w", MYNAME); +} + +static void +ignr_rw_deinit(void) +{ + fclose(fout); +} + +static void +ignr_write_track_hdr(const route_head *track) +{ + track_num++; + + if (track_num != track_index) return; + + ignr_fprintf(fout, "\t\n"); + ignr_fprintf(fout, "\t\t%d\n", track->rte_waypt_ct); + if (track->rte_desc != NULL) + ignr_fprintf(fout, "\t\t%s\n", track->rte_desc); + ignr_fprintf(fout, "\t\n"); +} + +static void +ignr_write_track_trl(const route_head *track) +{ +} + +static void +ignr_write_waypt(const waypoint *wpt) +{ + if (track_num != track_index) return; + + ignr_fprintf(fout, "\t\n"); + ignr_fprintf(fout, "\t\t%3.6f,%3.6f\n", wpt->latitude, wpt->longitude); + if (wpt->altitude != unknown_alt) + ignr_fprintf(fout, "\t\t%3.6f\n", wpt->altitude); + ignr_fprintf(fout, "\t\n"); +} + +static void +ignr_write(void) +{ + time_t now; + struct tm tm; + char buff[32]; + + if (index_opt != NULL) + { + track_index = atoi(index_opt); + if ((track_index < 1) || (track_index > track_count())) + fatal(MYNAME ": Invalid track index %d (we have currently %d track(s))!\n", + track_index, track_count()); + } + else + track_index = 1; + track_num = 0; + + now = current_time(); + tm = *localtime(&now); + + ignr_fprintf(fout, "\n"); + ignr_fprintf(fout, "\n"); + ignr_fprintf(fout, "\t\n"); + ignr_fprintf(fout, "\t\t1.1\n"); + ignr_fprintf(fout, "\t\tIHA03AA\n"); + + strftime(buff, sizeof(buff), "%d/%m/%Y", &tm); + ignr_fprintf(fout, "\t\t%s\n", buff); + strftime(buff, sizeof(buff), "%H:%M:%S", &tm); + ignr_fprintf(fout, "\t\t%s\n", buff); + + ignr_fprintf(fout, "\t\n"); + track_disp_all(ignr_write_track_hdr, ignr_write_track_trl, ignr_write_waypt); + ignr_fprintf(fout, "\n"); +} + +ff_vecs_t ignr_vecs = { + ff_type_file, + { ff_cap_none, ff_cap_read | ff_cap_write, ff_cap_none }, + ignr_rd_init, + ignr_rw_init, + ignr_rd_deinit, + ignr_rd_deinit, + ignr_read, + ignr_write, + NULL, + ignr_args, + CET_CHARSET_MS_ANSI, 1 +}; diff --git a/gpsbabel/vecs.c b/gpsbabel/vecs.c index a1656ee71..cd8a195d6 100644 --- a/gpsbabel/vecs.c +++ b/gpsbabel/vecs.c @@ -86,6 +86,7 @@ extern ff_vecs_t vitosmt_vecs; extern ff_vecs_t gdb_vecs; extern ff_vecs_t bcr_vecs; extern ff_vecs_t coto_vecs; +extern ff_vecs_t ignr_vecs; static vecs_t vec_list[] = { @@ -428,6 +429,12 @@ vecs_t vec_list[] = { NULL }, #endif + { + &ignr_vecs, + "ignrando", + "IGN Rando track files", + "rdn" + }, { NULL, NULL, -- 2.30.2